﻿/****************************************************************************************************
	Copyright (C) 2010 RapidWebDev Organization (http://rapidwebdev.org)
	Author: Eunge, Legal Name: Jian Liu, Email: eunge.liu@RapidWebDev.org

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ****************************************************************************************************/

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using AjaxControlToolkit;
using BaoJianSoft.Common;
using BaoJianSoft.RapidWeb.Properties;

namespace BaoJianSoft.RapidWeb.Controls
{
    /// <summary>
    /// Float file uploading panel bases on Flash.
    /// </summary>
    public class FlashUpload : WebControl
    {
        protected internal static IApplicationContext applicationContext = SpringContext.Current.GetObject<IApplicationContext>();

        private Label labelHeaderText;
        private LinkButton linkButtonOK;
        private DropDownList dropdownlistAttachmentType;
        private HtmlGenericControl flashObjectTagContainer;
        private ModalPopupExtender modelPopupExtender;

        /// <summary>
        /// Sets/gets feature which the file uploading belongs to.
        /// </summary>
        public string Feature { get; set; }

        /// <summary>
        /// Page url to receive uploading file.
        /// </summary>
        public string UploadPageUrl { get; set; }

        /// <summary>
        /// Header text
        /// </summary>
        public string HeaderText { get; set; }

        /// <summary>
        /// ID of target control to fire event to display dialog.
        /// </summary>
        public string TargetControlID { get; set; }

        /// <summary>
        /// True when allows multiple files uploaded.
        /// </summary>
        public bool AllowMultipleFiles
        {
            get
            {
                if (this.ViewState["AllowMultipleFiles"] == null) return true;
                return (bool)this.ViewState["AllowMultipleFiles"];
            }
            set { this.ViewState["AllowMultipleFiles"] = value; }
        }

        /// <summary>
        /// Gets uploading identifier.
        /// </summary>
        public string UploadingIdentifier
        {
            get
            {
                if (this.ViewState["UploadingIdentifier"] == null)
                    this.ViewState["UploadingIdentifier"] = Guid.NewGuid().ToString();

                return (string)this.ViewState["UploadingIdentifier"];
            }
            set { this.ViewState["UploadingIdentifier"] = value; }
        }

        /// <summary>
        /// Query strings setting to upload page url.
        /// </summary>
        protected IDictionary<string, string> QueryStrings
        {
            get
            {
                var queryStrings = this.ViewState["QueryStrings"] as IDictionary<string, string>;
                if (queryStrings == null)
                {
                    queryStrings = new Dictionary<string, string>();
                    this.ViewState["QueryStrings"] = queryStrings;
                }

                return queryStrings;
            }
            set { this.ViewState["QueryStrings"] = value; }
        }

        public FlashUpload()
        {
            this.UploadPageUrl = "/FileUpload.ashx";
            this.Width = new Unit("560px");
        }

        public event EventHandler<ListItemCollectionEventArgs> ReceivingFileTypes;
        public event EventHandler<UploadedFileEventArgs> Uploaded;
        public event EventHandler Cancelled;

        /// <summary>
        /// Raises the System.Web.UI.Control.Init event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            // Panel - Popup
            Panel panelPopup = new Panel()
            {
                ID = GetControlId("PanelPopup_FlashUpload"),
                CssClass = "modalpopup",
                Width = this.Width
            };

            panelPopup.Style.Add("display", "none");
            this.Controls.Add(panelPopup);

            // Panel - Popup header
            panelPopup.Controls.Add(this.CreatePanelHeaderControl());

            // Panel - File type selection
            var fileTypeSelection = this.CreateFileTypeControl();
            if (fileTypeSelection != null) panelPopup.Controls.Add(fileTypeSelection);

            // Panel - Flash Object Declaration
            this.flashObjectTagContainer = new HtmlGenericControl("div");
            panelPopup.Controls.Add(this.flashObjectTagContainer);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            this.ValidateProperties();

            this.labelHeaderText.Text = this.HeaderText;

            // ModelPopup Extender
            this.modelPopupExtender = new ModalPopupExtender()
            {
                ID = GetControlId("ModalPopupExtenderFlashUpload"),
                TargetControlID = this.TargetControlID,
                PopupControlID = GetControlId("PanelPopup_FlashUpload"),
                BackgroundCssClass = "modalbackground",
                DropShadow = true,
                OkControlID = GetControlId("LinkButtonOK_FlashUpload"),
                CancelControlID = GetControlId("LinkButtonClose_FlashUpload")
            };

            this.Controls.Add(this.modelPopupExtender);

            this.flashObjectTagContainer.InnerHtml = this.CreateFlashObjectTag();
            this.RegisterJavascriptCallback();
        }

        /// <summary>
        /// Set query string value.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        public void SetQueryString(string name, string value)
        {
            if (this.QueryStrings.ContainsKey(name)) this.QueryStrings.Remove(name);
            this.QueryStrings.Add(name, value);
        }

        /// <summary>
        /// Show model popup dialog.
        /// </summary>
        public void Show()
        {
            this.modelPopupExtender.Show();
        }

        /// <summary>
        /// Hide model popup dialog.
        /// </summary>
        public void Hide()
        {
            this.modelPopupExtender.Hide();
        }

        void linkButtonOK_Click(object sender, EventArgs e)
        {
            try
            {
                string uploadedFilesPath = WebUtility.ResolveFlashUploadFilesPath(this.Feature, this.UploadingIdentifier);
                string[] filePaths = Directory.GetFiles(uploadedFilesPath);

                if (this.Uploaded != null)
                    this.Uploaded(this, new UploadedFileEventArgs(filePaths));

                if (Directory.Exists(uploadedFilesPath))
                    Directory.Delete(uploadedFilesPath, true);
            }
            finally
            {
                this.UploadingIdentifier = null;
            }
        }

        void linkButtonClose_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.Cancelled != null)
                    this.Cancelled(this, new EventArgs());
            }
            finally
            {
                this.UploadingIdentifier = null;
            }
        }

        void dropdownlistAttachmentType_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.modelPopupExtender.Show();
        }

        private void RegisterJavascriptCallback()
        {
            LinkButton linkbutton = this.linkButtonOK;
            // allows the javascript function to do a postback and call the onClick method associated with the linkButton.
            string jscript = "function " + this.ID + "_OnUploadCompleted() {";
            jscript += string.Format("eval($('#{0}').attr('href'));", linkbutton.ClientID);
            jscript += "};";

            ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
            if (scriptManager == null || !scriptManager.IsInAsyncPostBack)
            {
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), string.Format("FileCompleteUpload_{0}", this.ID), jscript, true);
            }
            else
            {
                ScriptManager.RegisterClientScriptBlock(this, this.GetType(), string.Format("FileCompleteUpload_{0}", this.ID), jscript, true);
            }
        }

        private Control CreatePanelHeaderControl()
        {
            // Panel - Popup Header
            Panel panelPopupHeader = new Panel()
            {
                ID = GetControlId("PanelPopupHeader_FlashUploaded"),
                CssClass = "modalpopupheader",
            };

            // Panel - Popup Header - Inner Table
            HtmlTable htmlTable = new HtmlTable()
            {
                Border = 0,
                CellSpacing = 0,
                CellPadding = 0,
                Width = "100%",
            };

            panelPopupHeader.Controls.Add(htmlTable);

            HtmlTableRow htmlTableRow = new HtmlTableRow();
            htmlTable.Rows.Add(htmlTableRow);

            HtmlTableCell htmlTableCell = new HtmlTableCell("td") { Width = "70%" };
            htmlTableCell.Attributes["class"] = "label";
            htmlTableRow.Cells.Add(htmlTableCell);

            Image imageLabel = new Image() { ImageUrl = this.GetIconUrl() };
            htmlTableCell.Controls.Add(imageLabel);

            this.labelHeaderText = new Label();
            htmlTableCell.Controls.Add(this.labelHeaderText);

            htmlTableCell = new HtmlTableCell("td") { Width = "30%" };
            htmlTableCell.Attributes["class"] = "button";
            htmlTableCell.Style.Add("text-align", "right");
            htmlTableRow.Cells.Add(htmlTableCell);

            this.linkButtonOK = new LinkButton() { ID = GetControlId("LinkButtonOK_FlashUpload") };
            this.linkButtonOK.Click += new EventHandler(this.linkButtonOK_Click);
            htmlTableCell.Controls.Add(this.linkButtonOK);

            LinkButton linkButtonClose = new LinkButton() { ID = GetControlId("LinkButtonClose_FlashUpload"), Text = Resources.Ctrl_CloseButtonText };
            linkButtonClose.Click += new EventHandler(this.linkButtonClose_Click);
            htmlTableCell.Controls.Add(linkButtonClose);

            return panelPopupHeader;
        }

        private Control CreateFileTypeControl()
        {
            if (this.ReceivingFileTypes != null)
            {
                ListItemCollectionEventArgs e = new ListItemCollectionEventArgs();
                this.ReceivingFileTypes(this, e);

                if (e.ListItemCollection.Count > 0)
                {
                    Panel panelAttachmentType = new Panel() { ID = GetControlId("PanelAttachmentType"), CssClass = "modalpopupfiletypes" };
                    HtmlTable htmlTable = new HtmlTable() { CellPadding = 0, CellSpacing = 0, Width = "100%" };
                    panelAttachmentType.Controls.Add(htmlTable);

                    HtmlTableRow htmlTableRow = new HtmlTableRow();
                    htmlTable.Rows.Add(htmlTableRow);

                    HtmlTableCell htmlTableCell = new HtmlTableCell("td") { Width = "100px", InnerHtml = Resources.Ctrl_FlashUploadFileType + ": ", Align = "right" };
                    htmlTableCell.Attributes["class"] = "modalpopupfiletypes_label";
                    htmlTableRow.Cells.Add(htmlTableCell);

                    htmlTableCell = new HtmlTableCell("td");
                    htmlTableCell.Attributes["class"] = "modalpopupfiletypes_dropdownlist";
                    htmlTableRow.Cells.Add(htmlTableCell);

                    this.dropdownlistAttachmentType = new DropDownList() { ID = GetControlId("DropDownListAttachmentType"), Width = new Unit("160px"), AutoPostBack = true };
                    this.dropdownlistAttachmentType.SelectedIndexChanged += new EventHandler(dropdownlistAttachmentType_SelectedIndexChanged);
                    htmlTableCell.Controls.Add(this.dropdownlistAttachmentType);

                    foreach (ListItem listItem in e.ListItemCollection)
                    {
                        this.dropdownlistAttachmentType.Items.Add(listItem);
                    }

                    return panelAttachmentType;
                }
            }

            return null;
        }

        private string CreateFlashObjectTag()
        {
            StringBuilder objectTag = new StringBuilder();
            objectTag.AppendLine();
            objectTag.Append("<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0\" width=\"575\" height=\"375\" id=\"fileUpload\" align=\"middle\">");
            objectTag.AppendLine();
            objectTag.Append("<param name=\"allowScriptAccess\" value=\"sameDomain\" />");
            objectTag.AppendLine();
            objectTag.AppendFormat("<param name=\"movie\" value=\"{0}\" />", this.GetFlashMoiveUrl());
            objectTag.AppendLine();
            objectTag.Append("<param name=\"quality\" value=\"high\" />");
            objectTag.AppendLine();
            objectTag.Append("<param name=\"wmode\" value=\"transparent\">");
            objectTag.AppendLine();
            objectTag.AppendFormat("<param name=FlashVars value='uploadPage={0}&completeFunction={1}_OnUploadCompleted()'>", this.CreateUploadPageUrl(), this.ID);
            objectTag.AppendLine();
            objectTag.AppendFormat("<embed src=\"{0}\" ", this.GetFlashMoiveUrl());
            objectTag.AppendFormat("FlashVars='uploadPage={0}&completeFunction={1}_OnUploadCompleted()' ", this.CreateUploadPageUrl(), this.ID);
            objectTag.Append("quality=\"high\" wmode=\"transparent\" width=\"575\" height=\"375\" ");
            objectTag.Append("name=\"fileUpload\" align=\"middle\" allowScriptAccess=\"sameDomain\" ");
            objectTag.Append("type=\"application/x-shockwave-flash\" ");
            objectTag.Append("pluginspage=\"http://www.macromedia.com/go/getflashplayer\" />");
            objectTag.AppendLine();
            objectTag.Append("</object>");

            return objectTag.ToString();
        }

        private string CreateUploadPageUrl()
        {
            if (Kit.IsEmpty(this.Feature))
				throw new ArgumentNullException("Feature", Resources.Ctrl_FlashUploadFeatureNotSpecified);

            if (this.dropdownlistAttachmentType != null)
            {
                this.SetQueryString("ProductAttachmentTypeId", this.dropdownlistAttachmentType.SelectedValue);
            }

            this.SetQueryString("Feature", this.Feature);
			this.SetQueryString("UploadedBy", applicationContext.Identity != null ? applicationContext.Identity.Name : "");
            this.SetQueryString("UploadingIdentifier", this.UploadingIdentifier);

            StringBuilder queryString = new StringBuilder();
            var iterator = this.QueryStrings.GetEnumerator();
            while (iterator.MoveNext())
            {
                if (queryString.Length > 0) queryString.Append("&");
                queryString.AppendFormat("{0}={1}", iterator.Current.Key, HttpContext.Current.Server.UrlEncode(iterator.Current.Value));
            }

            string uploadPageUrl = null;
            if (this.UploadPageUrl.Contains('?'))
            {
                uploadPageUrl = string.Format("{0}&{1}", this.UploadPageUrl, queryString.ToString());
            }
            else
            {
                uploadPageUrl = string.Format("{0}?{1}", this.UploadPageUrl, queryString.ToString());
            }

            return HttpContext.Current.Server.UrlEncode(uploadPageUrl);
        }

        private void ValidateProperties()
        {
            if (string.IsNullOrEmpty(this.HeaderText))
            {
                throw new ArgumentException("HeaderText");
            }

            if (string.IsNullOrEmpty(this.TargetControlID))
            {
                throw new ArgumentException("TargetControlID");
            }
        }

        private string GetIconUrl()
        {
            return string.Format("{0}/App_Themes/{1}/Images/container-header.png", WebUtility.WebSiteBaseUrl, this.Page.Theme);
        }

        private string GetControlId(string id)
        {
            return this.ID + "_" + id;
        }

        private string GetFlashMoiveUrl()
        {
            string uploadType = this.AllowMultipleFiles ? "Multiple" : "Single";
            string directory = string.Format("/Flash/FileUpload/{0}/{1}", uploadType, Resources.Culture == null ? "en-US" : Resources.Culture.Name);
            if (!Directory.Exists(directory))
                directory = string.Format("/Flash/FileUpload/{0}/en-US", uploadType);

            return Path.Combine(directory, "FlashFileUpload.swf");
        }
    }

    /// <summary>
    /// Event argument for pulling ListItemCollection.
    /// </summary>
    public sealed class ListItemCollectionEventArgs : EventArgs
    {
        /// <summary>
        /// Get ListItemCollection container for callback to setup file types.
        /// </summary>
        public IList<ListItem> ListItemCollection { get; private set; }

        /// <summary>
        /// Construct ListItemCollection EventArgs
        /// </summary>
        /// <param name="listItemCollection"></param>
        public ListItemCollectionEventArgs()
        {
            this.ListItemCollection = new List<ListItem>();
        }
    }

    /// <summary>
    /// Event argument for uploaded file
    /// </summary>
    public sealed class UploadedFileEventArgs : EventArgs
    {
        /// <summary>
        /// Gets enumerable uploaded files.
        /// </summary>
        public IEnumerable<string> Files { get; private set; }

        /// <summary>
        /// Construct UploadedFileEventArgs
        /// </summary>
        /// <param name="files"></param>
        public UploadedFileEventArgs(IEnumerable<string> files)
        {
            this.Files = files;
        }
    }
}
